import java.awt.Point;
import java.util.ArrayList;

import com.speljohan.rsbot.script.Calculations;
import com.speljohan.rsbot.script.Methods;
import com.speljohan.rsbot.script.Random;
import com.speljohan.rsbot.script.wrappers.RSInterface;
import com.speljohan.rsbot.script.wrappers.RSInterfaceChild;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSPlayer;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class Pinball extends Random {
	public enum State {
		LEAVING, TAG
	}

	public static final int IFACE_PINBALL = 263;
	public static final int OBJ_EXIT = 15010;

	private static final int[] OBJ_PILLARS = { 15000, 15002, 15004, 15006,
			15008 };;

	private long lastTag;
	private RSTile lastTile;
	private State state;

	@Override
	public boolean activateCondition() {
		if (isLoggedIn() && getPillar() != null) {
			state = State.TAG;
			lastTag = System.currentTimeMillis();
			lastTile = new RSTile(0, 0);
			return true;
		}
		return false;
	}

	// Left-click only - stops right-clicking and canceling.
	@Override
	public boolean atTile(final RSTile tile, final String action) {
		try {
			// In case of one-button mode.
			if (atMenu(action)) {
				return true;
			}

			final Point location = Calculations.tileToScreen(tile);
			if (location.x == -1 || location.y == -1) {
				return false;
			}
			moveMouse(location, 3, 3);
			if (getMenuItems().get(0).toLowerCase().contains(
					action.toLowerCase())) {
				clickMouse(location, 3, 3, true);
			} else {
				return false;
			}
			wait(random(500, 1000));
			while (true) {
				if (!getMyPlayer().isMoving()) {
					break;
				}
				wait(random(500, 1000));
			}
			return true;
		} catch (final Exception e) {
			return false;
		}
	}

	private RSTile calculateExitTile() {
		final RSObject air = findObject(15005);

		if (air == null) {
			return null;
		}

		final int x = air.getLocation().getX();
		final int y = air.getLocation().getY() - 13;
		return new RSTile(x, y);
	}

	private RSTile[] generatePath(final int destinationX, final int destinationY) {
		int startX = getMyPlayer().getLocation().getX();
		int startY = getMyPlayer().getLocation().getY();
		double dx, dy;

		final ArrayList<RSTile> list = new ArrayList<RSTile>();

		list.add(new RSTile(startX, startY));
		while (Math.hypot(destinationY - startY, destinationX - startX) > 2) {
			dx = destinationX - startX;
			dy = destinationY - startY;

			while (Math.hypot(dx, dy) > 2) {
				dx *= .95;
				dy *= .95;
			}
			startX += (int) dx;
			startY += (int) dy;
			list.add(new RSTile(startX, startY));
		}
		list.add(new RSTile(destinationX, destinationY));
		return list.toArray(new RSTile[list.size()]);
	}

	@Override
	public String getAuthor() {
		return "Aelin && LM3";
	}

	@Override
	public String getName() {
		return "Pinball";
	}

	private RSObject getPillar() {
		return findObject(16, Pinball.OBJ_PILLARS);
	}

	private int getScore() {
		final RSInterfaceChild score = RSInterface.getChildInterface(
				Pinball.IFACE_PINBALL, 1);
		return Integer.parseInt(score.getText().split(" ")[1]);
	}

	@Override
	public double getVersion() {
		return 2;
	}

	@Override
	public int loop() {
		final RSPlayer myPlayer = getMyPlayer();
		if (myPlayer.isMoving() || myPlayer.getAnimation() != -1) {
			lastTag = System.currentTimeMillis();
			wait(500);
			return random(200, 300);
		}

		if (state.equals(State.TAG)) {
			final int score = getScore();

			if (score >= 10) {
				state = State.LEAVING;
				return 0;
			}

			final RSObject pillar = getPillar();
			final RSTile tile = pillar.getLocation();

			if (tile.equals(lastTile)
					&& System.currentTimeMillis() - lastTag < 2000) {
				return random(300, 400);
			}

			if (recheckPillar(tile)) {
				if (atObject(pillar, "Tag")) {
					lastTile = tile;
					lastTag = System.currentTimeMillis();
					return random(500, 600);
				}
			}
		} else if (state.equals(State.LEAVING)) {
			final RSTile exit = calculateExitTile();

			if (exit == null) {
				return -1;
			}

			if (distanceTo(exit) > 3) {
				walkGroundPath(generatePath(exit.getX(), exit.getY()));
				return random(500, 600);
			} else {
				atTile(exit, "Exit");
			}
		}
		return 0;
	}

	private boolean recheckPillar(final RSTile tile) {
		final RSObject obj = getObjectAt(tile);
		for (final int i : Pinball.OBJ_PILLARS) {
			if (i == obj.getID()) {
				return true;
			}
		}
		return false;
	}

	private boolean walkGroundPath(RSTile[] path) {
		path = randomizePath(path, 1, 1);
		final RSTile start = getMyPlayer().getLocation();

		if (Methods.distanceBetween(start, path[path.length - 1]) < 2) {
			return true;
		}

		for (int i = path.length - 1; i > 0; i--) {
			if (tileOnScreen(path[i])) {
				atTile(path[i], "Walk");
				return false;
			}
		}

		throw new RuntimeException();
	}
}